<template>
  <!-- {{ [...typeSlotNames, ...slotNames,...cellRenderNames] }} -->
  <div :class="tableWrapperClass">
    <vxe-grid
      ref="gridRef"
      v-bind="gridOptions"
      @toolbar-tool-click="toolbarToolClickEvent"
      @toolbar-button-click="toolbarButtonClickEvent"
      @page-change="pageChangeEvent"
      @radio-change="radioChangeEvent"
      @checkbox-change="checkboxChangeEvent"
      @checkbox-all="checkboxAllEvent"
      @sort-change="sortChangeEvent"
    >
      <!-- 查询表单 -->
      <template #form v-if="formOptions">
        <y-form
          ref="formRef"
          :options="yFormOption"
          @submit="formSubmit"
          @reset="formReset"
        >
          <!-- 插槽 -->
          <template #[slot]="{ data }" v-for="slot in formSlotNames">
            <!-- 传入 slotNames -->
            <slot :name="slot" v-bind="{ data }"></slot>
          </template>
        </y-form>
      </template>

      <!-- 顶部 -->
      <template #top>
        <slot name="top"></slot>
      </template>
      <!-- 表格左边区域 -->
      <template #left>
        <slot name="left"></slot>
      </template>
      <!-- 表格右边区域 -->
      <template #right>
        <slot name="right"></slot>
      </template>
      <!-- 底部区域 -->
      <template #bottom>
        <slot name="bottom"></slot>
      </template>
      <!-- 左侧区域 -->
      <template #asideLeft>
        <slot name="asideLeft"></slot>
      </template>
      <!-- 右侧区域 -->
      <template #asideRight>
        <slot name="asideRight"></slot>
      </template>

      <!-- 单选header插槽 -->
      <template #radio_header>
        <vxe-button mode="text" @click="clearRadioRow" :disabled="!selectRow">
          取消
        </vxe-button>
      </template>

      <!-- 插槽 -->
      <template
        #[slot]="{ row, column }"
        v-for="slot in [...typeSlotNames, ...slotNames, ...cellRenderNames]"
      >
        <!-- 传入 slotNames -->
        <slot :name="slot" v-bind="{ row, column }">
          <!-- 内置 cellRenderNames -->
          <default-slots
            v-bind="{ slotName: slot, column, row }"
          ></default-slots>
        </slot>
      </template>
    </vxe-grid>
    <!-- 导出 -->
    <ExportContent ref="exportContentRef" :export-config="exportConfig" />

    <!-- 导入 -->
    <ImportDailog ref="importDailogRef" :import-config="importConfig" />
  </div>
</template>

<script>
import { cloneDeep } from '@/utils'
import { initOptions } from './unit/init'
import defaultOptions from './unit/default-options'
import router from '@/router'
import ExportContent from './components/ExportImport/ExportContent.vue'
import exportImportMixin from './mixins/export-import'
import ImportDailog from './components/ExportImport/ImportDailog.vue'
import defaultSlots from './components/defaultSlots'
import { getDictItems } from '@/utils/dict'

export default {
  components: { ExportContent, ImportDailog, defaultSlots },
  mixins: [exportImportMixin],
  props: {
    formOptions: Object,
    tableOptions: Object,
    // 获取数据方法
    dataMethod: Function,
    // 默认查询数据
    defaultQueryData: Object,
    // 导出参数
    exportConfig: Object,
    // 导入参数
    importConfig: Object
  },
  watch: {
    tableOptions: {
      deep: true,
      immediate: true,
      handler(val) {
        const TABLE_ID = router.currentRoute.fullPath
        const cloneDeepVal = cloneDeep(val)
        const {
          columns,
          dictMaps,
          toolbarConfig,
          slotNames,
          typeSlotNames,
          formSlotNames,
          cellRenderNames,
          radioConfig,
          rowConfig,
          checkboxConfig
        } = initOptions(this)

        this.slotNames = slotNames
        this.typeSlotNames = typeSlotNames
        this.cellRenderNames = cellRenderNames
        this.formSlotNames = formSlotNames

        this.dictMaps = dictMaps
        const gridOptions = {
          id: TABLE_ID,
          ...defaultOptions,
          ...cloneDeepVal,
          toolbarConfig,
          radioConfig,
          checkboxConfig,
          rowConfig,
          columns
        }

        this.gridOptions = gridOptions
      }
    }
  },
  computed: {
    tableWrapperClass() {
      const map = {
        auto: 'h-full'
      }
      return map[this.gridOptions.height]
    },
    yFormOption() {
      return {
        titleWidth: 'auto',
        span: '',
        ...this.formOptions,
        items: [
          ...this.formOptions.items,
          {
            itemRender: {
              name: 'VxeButtonGroup',
              options: [
                {
                  icon: 'vxe-icon-search',
                  type: 'submit',
                  content: '查询',
                  status: 'primary'
                },
                { icon: 'vxe-icon-refresh', type: 'reset', content: '重置' }
              ]
            }
          }
        ]
      }
    },

    queryFormData() {
      if (this.$refs.formRef) {
        return this.$refs.formRef.formOptions.data
      }
      return {}
    },
    tablePage() {
      return this.$refs.gridRef.tablePage
    },
    // 查询参数（表单+分页参数）
    queryData() {
      return {
        ...this.queryFormData,
        ...this.tablePage
      }
    },
    // 单选数据
    selectRow: {
      get() {
        return (
          this.$refs.gridRef.getRadioRecord() ||
          this.$refs.gridRef.getRadioReserveRecord()
        )
      }
    },
    // 多选数据
    selectRows() {
      return this.$refs.gridRef
        .getCheckboxRecords()
        .concat(this.$refs.gridRef.getCheckboxReserveRecords())
    }
  },
  mounted() {
    // 设置查询参数
    this.setDefaultOptions()
  },
  data() {
    return {
      slotNames: [], // 插槽列表
      cellRenderNames: [], // cellRender 插槽列表
      typeSlotNames: [], // 根据自定义type 属性生成的插槽列表
      formSlotNames: [], // 查询表单的插槽列表
      gridOptions: {},
      dictMaps: {} // 字典地图
    }
  },
  methods: {
    // 查询表单 查询
    formSubmit() {
      this.loadData()
    },
    // 查询表单重置
    formReset() {
      this.loadData()
    },
    toolbarButtonClickEvent(e) {
      this.$emit('toolbar-button-click', e)
    },
    // 单选事件
    radioChangeEvent() {
      this.$emit('radio-change', this.selectRow)
    },
    /**
     * 触发复选框变化事件的处理函数
     * 当复选框的选中状态发生变化时，此函数会被调用
     * 它通过$emit方法将复选框的变化事件和数据传递给父组件
     *
     * @param {Event} e - 复选框变化事件对象，包含事件的具体信息
     */
    checkboxChangeEvent({ records }) {
      this.$emit('checkbox-change', records)
    },
    // 全选事件
    checkboxAllEvent({ records }) {
      this.$emit('checkbox-change', records)
    },
    // 排序事件
    sortChangeEvent(e) {
      this.$emit('sort-change', e)
    },
    toolbarToolClickEvent(e) {
      const { code } = e
      this.$emit('toolbar-tool-click', e)
      switch (code) {
        case 'yExportCode':
          this.openExport()
          break
        case 'yImportCode':
          this.openImport()
          break
        case 'yRefreshCode':
          this.loadData()
          break
        default:
          break
      }
    },

    // 分页变化
    async pageChangeEvent({ pageSize, currentPage }) {
      const isChangePageSize =
        this.gridOptions.pagerConfig.pageSize !== pageSize
      this.setPageData({
        currentPage: isChangePageSize ? 1 : currentPage,
        pageSize
      })
      await this.loadData()

      this.$emit('page-change', { pageSize, currentPage })
    },
    // 读取表格数据
    loadData() {
      return new Promise((resolve, reject) => {
        try {
          this.$set(this.gridOptions, 'loading', true)

          const { params: defaultParams = {} } = this.defaultQueryData || {}
          this.$nextTick(async () => {
            const query = {
              ...this.queryData,
              ...defaultParams,
              pageNum: this.queryData.currentPage
            }

            const queryData = cloneDeep(query)
            delete queryData.currentPage

            const {
              data,
              total,
              pageNum: currentPage,
              pageSize
            } = await this.dataMethod(queryData)
            await this.setData({ data, total, currentPage, pageSize })
            resolve(true)
          })
        } catch (error) {
          reject(error)
        }
      })
    },
    async setdictCodeData(data) {
      if (!Array.isArray(data) || !Object.keys(this.dictMaps).length) {
        return cloneDeep(data)
      }

      const dictData = cloneDeep(data)
      const dictCache = {}

      for (const item of dictData) {
        for (const [field, dictCode] of Object.entries(this.dictMaps)) {
          if (field in item) {
            try {
              if (!dictCache[dictCode]) {
                dictCache[dictCode] = await getDictItems(dictCode)
              }
              const dictItems = dictCache[dictCode]
              const matchingItem = dictItems.find(
                (d) => d.value === item[field]
              )
              item[field + '_dictText'] = matchingItem
                ? matchingItem.name
                : null
            } catch (error) {
              console.error(
                `Error processing field ${field} with dictCode ${dictCode}:`,
                error
              )
              item[field + '_dictText'] = null // 设置默认值或跳过
            }
          }
        }
      }

      return dictData
    },
    // 设置表格数据
    async setData({ data, total, currentPage, pageSize }) {
      const dictData = await this.setdictCodeData(data)
      this.$set(this.gridOptions, 'data', dictData)

      this.setPageData({
        total,
        currentPage,
        pageSize
      })
      this.$set(this.gridOptions, 'loading', false)
      return true
    },
    // 设置查询表单数据
    setFormData(data) {
      this.$refs.formRef.setData(data)
    },
    // 设置分页数据
    setPageData(data) {
      this.gridOptions.pagerConfig = {
        ...this.gridOptions.pagerConfig,
        ...data
      }
    },
    // 设置默认查询参数
    setDefaultOptions() {
      if (!this.defaultQueryData) return
      const { form, page } = this.defaultQueryData
      if (form && this.formOptions) {
        this.setFormData(form)
      }
      if (page) {
        this.setPageData(page)
      }
    },
    // 用于 type=radio 单选框，设置指定行为选中状态
    setRadioRowKey(key) {
      this.$refs.gridRef.setRadioRowKey(key)
    },
    // 设置单选行
    setRadioRow(row) {
      this.$refs.gridRef.setRadioRow(row)
    },
    // 设置复选框行
    setCheckboxRow(rows, checked = true) {
      this.$refs.gridRef.setCheckboxRow(rows, checked)
    },
    /**
     * 设置复选框行的关键字
     * 此函数用于更新表格中复选框选中的行的关键字
     * 它接受一个关键字数组作为参数，并将其传递给gridRef引用的组件的相应方法
     * @param {Array} keys - 要设置的关键字数组，默认为空数组
     * @param {Array} checkbox - 要设置的选中状态 true or false，默认为true
     *
     */
    setCheckboxRowKey(key = '', checked = true) {
      this.$refs.gridRef.setCheckboxRowKey(key, checked)
    },
    // 清除选中的行 radio
    clearRadioRow() {
      this.$refs.gridRef.clearRadioRow()
      this.$refs.gridRef.clearRadioReserve()
      this.$emit('radio-change', this.selectRow)
    },
    // 清除选中的行 checkbox
    clearCheckboxRow() {
      this.$refs.gridRef.clearCheckboxRow()
      this.$refs.gridRef.clearCheckboxReserve()
      this.$emit('checkbox-change', this.selectRows)
    },

    /**
     * 获取选中的记录
     * 该函数根据传入的类型参数，获取界面上选中的记录可以是单选记录，也可以是多选记录
     * @param {string} type - 选中类型，可以是 'radio' 表示单选，或者是其他值表示多选
     * @returns {Object|Object[]} - 返回选中的记录对象如果是多选，返回数组如果是单选，返回单个对象发生错误时返回 null
     */
    getSelectRecord(type) {
      try {
        // 假设 selectedRecord 是从某个地方获取的选中记录
        let selectedRecord

        // 根据传入的 type 参数，选择不同的方法获取选中记录
        switch (type) {
          case 'radio':
            // 获取单选记录
            const record = {
              ...this.$refs.gridRef.getRadioReserveRecord(),
              ...this.$refs.gridRef.getRadioRecord()
            }
            selectedRecord = record
            break

          default:
            // 获取多选记录
            selectedRecord = this.$refs.gridRef
              .getCheckboxRecords()
              .concat(this.$refs.gridRef.getCheckboxReserveRecords())
            break
        }
        // 返回选中的记录
        return selectedRecord
      } catch (error) {
        // 捕获错误并打印错误信息
        console.error('获取选中记录时发生错误:', error)
        // 发生错误时返回 null
        return null
      }
    }
  }
}
</script>

<style lang="scss">
.y-toolbar-config .vxe-tools--wrapper {
  padding-right: 0.72em;
  flex: none;
}

.vxe-pager--sizes {
  width: 9rem !important;
}
</style>
